package com.wjh.service.impl;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.wjh.common.BaseInfo;
import com.wjh.common.CommonMethods;
import com.wjh.common.Constants;
import com.wjh.common.LockConstant;
import com.wjh.enums.PayModeEnum;
import com.wjh.enums.PayStateEnum;
import com.wjh.goods.entity.GoodsEntity;
import com.wjh.mapper.IOrderDetailMapper;
import com.wjh.mapper.IOrderMapper;
import com.wjh.order.dto.OrderDetailDto;
import com.wjh.order.entity.OrderDetailEntity;
import com.wjh.order.entity.OrderEntity;
import com.wjh.order.enums.StateEnum;
import com.wjh.order.request.OrderGoodsRequest;
import com.wjh.order.request.QueryOrderPageRequest;
import com.wjh.order.request.SaveOrderRequest;
import com.wjh.order.request.UpdateOrderPayStateRequest;
import com.wjh.service.ICommonService;
import com.wjh.service.IOrderService;
import com.wjh.util.DateUtil;

import lombok.extern.slf4j.Slf4j;

/**
 * 订单Service实现类
 * 
 * @author wenjianhai
 * @date 2023/6/22
 * @since JDK 17
 */
@Slf4j
@Service
public class OrderServiceImpl implements IOrderService {

	@Autowired
	private ICommonService commonService;

	@Autowired
	private IOrderMapper orderMapper;

	@Autowired
	private IOrderDetailMapper orderDetailMapper;

	@Autowired
	private RedissonClient redissonClient;

	/**
	 * 商品下单
	 *
	 * @param request  下单请求参数
	 * @param baseInfo 下单人
	 * @date 2023-06-22
	 * @author wenjianhai
	 * @since JDK 17
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public void save(SaveOrderRequest request, BaseInfo baseInfo) {
		// 购买的商品
		List<OrderGoodsRequest> goodsList = request.getGoodsList();

		// 订单Guid
		String orderGuid = CommonMethods.getMeUUID();
		// 订单号
		String orderNo = this.getOrderNo();

		// 订单总金额（单位：分）
		long totalAmount = 0;
		// 订单优惠金额（单位：分）
		long discount = 0;

		// 订单明细
		List<OrderDetailEntity> orderDetailList = new ArrayList<>(goodsList.size());
		OrderDetailEntity orderDetail = null;
		// 订单明细编号
		int detailNo = 0;

		for (OrderGoodsRequest goodsRequest : goodsList) {
			// 查询商品
			GoodsEntity goods = commonService.queryGoods(goodsRequest.getGoodsGuid());

			if (goods == null) {
				log.error("商品下单,商品已不存在.商品Guid:{}, 商品名称:{}", goodsRequest.getGoodsGuid(), goodsRequest.getGoodsName());
				throw new RuntimeException(String.format("%s 已不存在", goodsRequest.getGoodsName()));
			}
			if (goodsRequest.getBuyCount().intValue() > goods.getStock().intValue()) {
				log.error("商品下单,商品库存不足.商品Guid:{}, 商品名称:{}, 库存:{}, 购买数量:{}", goodsRequest.getGoodsGuid(),
						goodsRequest.getGoodsName(), goods.getStock(), goodsRequest.getBuyCount());
				throw new RuntimeException(String.format("%s 库存不足", goodsRequest.getGoodsName()));
			}
			// 该商品的购买总金额 = 售价（单位：分） * 购买数量
			long goodsBuyAmount = goods.getSellPrice() * goodsRequest.getBuyCount();
			// 订单总金额（单位：分）= 每个商品的购买总金额总和
			totalAmount += goodsBuyAmount;
			// 订单优惠金额（单位：分）
			discount += (goodsRequest.getDiscount() == null ? 0L : goodsRequest.getDiscount());

			// 订单明细编号
			detailNo++;
			// 订单明细
			orderDetail = this.setOrderDetail(goodsRequest, orderGuid, orderNo, goods, detailNo, baseInfo);

			orderDetailList.add(orderDetail);
		}
		// 订单信息
		OrderEntity order = new OrderEntity();
		order.setOrderGuid(orderGuid);
		order.setOrderNo(orderNo);
		order.setTotalAmount(totalAmount);
		order.setDiscount(discount);
		order.setActualAmount(order.getTotalAmount() - order.getDiscount());
		order.setPayMode(PayModeEnum.ZFB.getCode());
		order.setPayState(PayStateEnum.UN_PAY.getCode());
		order.setState(StateEnum.NORMAL.getCode());
		order.setCreatorCode(baseInfo.getUserCode());
		order.setCreatorName(baseInfo.getUserName());
		order.setUpdaterCode(baseInfo.getUserCode());
		order.setUpdaterName(baseInfo.getUserName());

		// 保存订单信息
		orderMapper.save(order);

		// 保存订单明细
		orderDetailMapper.batchSave(orderDetailList);

		log.info("商品下单-结束.请求参数:{}, 下单人编码:{}, 下单人:{}", JSON.toJSONString(request), baseInfo.getUserCode(),
				baseInfo.getUserName());
	}

	@Override
	public Page<OrderEntity> page(QueryOrderPageRequest request) {
		if (request.getPageNum() <= 0) {
			request.setPageNum(Constants.DEFAULT_PAGE_NUM);
		}
		if (request.getPageSize() <= 0) {
			request.setPageSize(Constants.DEFAULT_PAGE_SIZE);
		}
		// 数据创建 开始日期（格式：yyyy-MM-dd）
		String beginDate = request.getBeginDate();
		// 数据创建 截止日期（格式：yyyy-MM-dd）
		String endDate = request.getEndDate();

		if (StringUtils.isNotBlank(beginDate) && beginDate.trim().length() == Constants.DATE_LENGTH) {
			request.setBeginDate(beginDate.trim() + " 00:00:00");
		}
		if (StringUtils.isNotBlank(endDate) && endDate.trim().length() == Constants.DATE_LENGTH) {
			request.setEndDate(endDate.trim() + " 23:59:59");
		}
		// 分页插件
		Page<OrderEntity> page = new Page<>(request.getPageNum(), request.getPageSize());
		// 查询数据
		return orderMapper.page(request, page);
	}

	/**
	 * 查询订单及其详情
	 *
	 * @param orderGuid 订单Guid
	 * @return OrderDetailDto
	 * @date 2023-06-26
	 * @author wenjianhai
	 * @since JDK 17
	 */
	@Override
	public OrderDetailDto queryOrderAndDetails(String orderGuid) {
		return StringUtils.isBlank(orderGuid) ? null : orderMapper.queryOrderAndDetails(orderGuid);
	}

	@Override
	public void updatePayState(UpdateOrderPayStateRequest request) {
		// 分布式锁
		RLock lock = null;

		try {
			String rdsKey = String.format(LockConstant.UPDATE_ORDER_PAY_STATE_LOCK_NAME, request.getOrderGuid());
			// 分布式锁
			lock = redissonClient.getLock(rdsKey);

			if (!lock.tryLock(LockConstant.UPDATE_ORDER_PAY_STATE_LOCK_WAIT_TIME,
					LockConstant.UPDATE_ORDER_PAY_STATE_LOCK_LEASE_TIME, TimeUnit.SECONDS)) {
				log.info("更新订单的支付状态,获取锁失败.rdsKey:{}", rdsKey);
				if (lock.isLocked()) {
					lock.unlock();
				}
				return;
			}
			orderMapper.updatePayState(request.getOrderGuid(), request.getPayState(), request.getPayMode());
		} catch (Exception e) {
			log.error(String.format("更新订单的支付状态-失败.请求参数:%s", JSON.toJSONString(request)), e);
			throw new RuntimeException(e.getMessage());
		} finally {
			if (lock != null && lock.isLocked()) {
				lock.unlock();
			}
		}
	}

	/**
	 * 设置订单明细
	 *
	 * @date 2023-06-23
	 * @param goodsRequest 下单的商品信息
	 * @param orderGuid    订单Guid
	 * @param orderNo      订单号
	 * @param goods        商品信息
	 * @param detailNo     订单明细编号
	 * @param baseInfo     下单人
	 * @return OrderDetailEntity
	 * @since JDK 17
	 * @author wenjianhai
	 */
	private OrderDetailEntity setOrderDetail(OrderGoodsRequest goodsRequest, String orderGuid, String orderNo,
			GoodsEntity goods, int detailNo, BaseInfo baseInfo) {
		// 订单明细
		OrderDetailEntity orderDetail = new OrderDetailEntity();
		orderDetail.setDetailGuid(CommonMethods.getMeUUID());
		if (detailNo < 10) {
			orderDetail.setDetailNo(orderNo + "0" + detailNo);
		} else {
			orderDetail.setDetailNo(orderNo + detailNo);
		}
		orderDetail.setOrderGuid(orderGuid);
		orderDetail.setOrderNo(orderNo);
		orderDetail.setGoodsGuid(goodsRequest.getGoodsGuid());
		orderDetail.setGoodsCode(goods.getGoodsCode());
		orderDetail.setGoodsName(goods.getGoodsName());
		orderDetail.setPrice(goods.getPrice());
		orderDetail.setSellPrice(goods.getSellPrice());
		orderDetail.setBuyCount(goodsRequest.getBuyCount());
		orderDetail.setTotalAmount(goods.getSellPrice() * goodsRequest.getBuyCount());
		orderDetail.setDiscount(goodsRequest.getDiscount());
		orderDetail.setActualAmount(orderDetail.getTotalAmount() - orderDetail.getDiscount());
		orderDetail.setPayMode(PayModeEnum.ZFB.getCode());
		orderDetail.setPayState(PayStateEnum.UN_PAY.getCode());
		orderDetail.setState(StateEnum.NORMAL.getCode());
		orderDetail.setCreatorCode(baseInfo.getUserCode());
		orderDetail.setCreatorName(baseInfo.getUserName());
		orderDetail.setUpdaterCode(baseInfo.getUserCode());
		orderDetail.setUpdaterName(baseInfo.getUserName());

		return orderDetail;
	}

	private String getOrderNo() {
		String now = DateUtil.format(new Date(), "yyyyMMddHHmmssS");
		return now.concat(CommonMethods.getNumber(4));
	}
}
